package com.thghh;

import java.math.BigDecimal;

/** 把输入的金额转换为汉语中人民币的大写 */
public class NumberToCN {
  public static final String EMPTY = "";
  public static final String DOT = ".";
  /** 中文大写数字 */
  private static final String[] NUMBERS = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
  /** 中文小写数字 */
  private static final String[] NUMBERS_CN = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
  /** 整数部分的单位 */
  private static final String[] INTEGER = {
    "元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "万", "拾", "佰", "仟"
  };
  /** 小数部分的单位 */
  private static final String[] DECIMAL = {"角", "分"};

  /**
   * 转换为大写的中文金额
   *
   * @param amount 数量
   * @return {@link String }
   * @author pengzhikang
   * @date 2024/06/14 17:52
   */
  public static String toChinese(BigDecimal amount) {
    if (amount == null) {
      throw new IllegalArgumentException("金额不能为空");
    }
    if (BigDecimal.ZERO.equals(amount)) {
      return NUMBERS[0];
    }
    // 判断金额数字中是否存在负号"-"
    boolean flag = false;
    if (amount.signum() == -1) {
      flag = true;
      amount = amount.abs();
    }

    // 去前导零、尾零
    amount = amount.stripTrailingZeros();
    String[] separateNum = separateNum(amount.toPlainString());
    // 整数部分
    String integers = separateNum[0];
    // 小数部分
    String decimals = separateNum[1];

    boolean isWan = isWan5(integers);

    // 返回最终的大写金额
    StringBuilder result = new StringBuilder();
    if (flag) {
      // 如果是负数，加上"负"
      result.append("负");
    }
    result.append(getChineseInteger(integers, isWan));
    if (!decimals.equals(EMPTY)) {
      result.append(getChineseDecimal(decimals));
    } else {
      result.append("整");
    }
    return result.toString();
  }

  /**
   * 分离整数部分和小数部分
   *
   * @param str
   * @return
   */
  private static String[] separateNum(String str) {
    // 整数部分数字
    String integerStr;
    // 小数部分数字
    String decimalStr;
    int dotIndex = str.indexOf(DOT);
    if (dotIndex > 0) {
      integerStr = str.substring(0, dotIndex);
      decimalStr = str.substring(dotIndex + 1);
    } else if (dotIndex == 0) {
      integerStr = EMPTY;
      decimalStr = str.substring(1);
    } else {
      integerStr = str;
      decimalStr = EMPTY;
    }
    return new String[] {integerStr, decimalStr};
  }

  /**
   * 将整数部分转为大写的金额
   *
   * @param integers 整数部分数字
   * @param isWan 整数部分是否已经是达到【万】
   * @return
   */
  public static String getChineseInteger(String integers, boolean isWan) {
    StringBuilder chineseInteger = new StringBuilder(EMPTY);
    int length = integers.length();
    if (length == 1 && integers.charAt(0) == '0') {
      return EMPTY;
    }
    for (int i = 0; i < length; i++) {
      // '0' == 48，当前金额分位数值
      int n = integers.charAt(i) - '0';
      // 金额单元下标
      int k = length - i;
      if (n == 0) {
        String key = EMPTY;
        if (k == 13) {
          // 万（亿）
          key = INTEGER[4];
        } else if (k == 9) {
          // 亿
          key = INTEGER[8];
        } else if (k == 5 && isWan) {
          // 万
          key = INTEGER[4];
        } else if (k == 1) {
          // 元
          key = INTEGER[0];
        }
        // 10300，这种情况补零
        if (k > 1 && integers.charAt(i + 1) != '0') {
          key = NUMBERS[0];
        }
        if (!EMPTY.equals(key)) {
          chineseInteger.append(key);
        }
      } else {
        chineseInteger.append(NUMBERS[n]).append(INTEGER[k - 1]);
      }
    }
    return chineseInteger.toString();
  }

  /**
   * 将小数部分转为大写的金额
   *
   * @param decimals 小数部分的数字
   * @return
   */
  private static String getChineseDecimal(String decimals) {
    StringBuilder chineseDecimal = new StringBuilder(EMPTY);
    int length = Math.min(decimals.length(), 2);
    for (int i = 0; i < length; i++) {
      // '0' == 48
      int n = decimals.charAt(i) - 48;
      if (n != 0) {
        chineseDecimal.append(NUMBERS[n]).append(DECIMAL[i]);
      }
    }
    return chineseDecimal.toString();
  }

  /**
   * 判断当前整数部分是否已经是达到【万】
   *
   * @param integerStr 整数部分数字
   * @return
   */
  private static boolean isWan5(String integerStr) {
    int length = integerStr.length();
    if (length > 4) {
      String subInteger;
      if (length > 8) {
        subInteger = integerStr.substring(length - 8, length - 4);
      } else {
        subInteger = integerStr.substring(0, length - 4);
      }
      return Integer.parseInt(subInteger) > 0;
    } else {
      return false;
    }
  }
}
